home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / os2 / pmnos11s / mbuf.c < prev    next >
C/C++ Source or Header  |  1993-07-30  |  14KB  |  608 lines

  1. /* mbuf (message buffer) primitives
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Mods by G1EMM
  5.  */
  6.  
  7. #include <stdio.h>
  8. #if !defined(OS2)
  9. #include <dos.h>    /* TEMP */
  10. #include <alloc.h>
  11. #endif
  12. #include "global.h"
  13. #include "mbuf.h"
  14. #include "proc.h"
  15. #include "config.h"
  16.  
  17. /* Interrupt buffer pool */
  18. int Intqlen;            /* Number of free mbufs on Intq */
  19. struct mbuf *Intq;        /* Mbuf pool for interrupt handlers */
  20. struct mbuf *Garbq;        /* List of buffers freed at interrupt time */
  21. long Ibuffail;            /* Allocate failures */
  22. int Iminfree  = -1;        /* minimum free buffers */
  23.  
  24. void
  25. refiq()
  26. {
  27. #if !defined(OS2)
  28.     register struct mbuf *bp;
  29.     char i_state;
  30. #ifdef    PI        /* Temp hack to satisfy PI DMA requirements */
  31.     int32 dma_abs;    /* TEMP */
  32.     int16 dma_page;    /* TEMP */
  33. #endif
  34.  
  35.     /* Empty the garbage */
  36.     if(Garbq != NULLBUF){
  37.         i_state = dirps();
  38.         bp = Garbq;
  39.         Garbq = NULLBUF;
  40.         restore(i_state);
  41.         free_p(bp);
  42.     }
  43.     /* Replenish interrupt buffer pool */ /* G1EMM and HB9RWM fix */
  44.     while((Intqlen < Nibufs) && (Memthresh < availmem()) ){
  45. #ifdef notdef
  46.     while(Intqlen < Nibufs){
  47. #endif
  48.         if((bp = alloc_mbuf(Ibufsize)) == NULLBUF)
  49.             break;
  50. #ifdef    PI        /* Temp hack to satisfy PI DMA requirements */
  51.         dma_abs = ((long)FP_SEG(bp->data) << 4) + (long)FP_OFF(bp->data);
  52.         dma_page = dma_abs >> 16;
  53.         if(((dma_abs+Ibufsize) >> 16) != dma_page){
  54.             i_state = dirps();
  55.             bp->next = Garbq;
  56.             Garbq = bp;
  57.             restore(i_state);
  58.             continue;
  59.         }
  60. #endif
  61.  
  62.         i_state = dirps();
  63.         bp->next = Intq;
  64.         Intq = bp;
  65.         Intqlen++;
  66.         restore(i_state);
  67.     }
  68.     if(Iminfree == -1)
  69.         Iminfree = Intqlen;
  70. #endif
  71. }
  72.  
  73. void
  74. iqstat()
  75. {
  76.     tprintf("Intqlen %u Ibufsize %u Iminfree %u Ibuffail %lu\n",
  77.         Intqlen,Ibufsize,Iminfree,Ibuffail);
  78. }
  79. void
  80. iqclear()
  81. {
  82. #if !defined(OS2)
  83.     Ibuffail = 0;
  84.     Iminfree = -1;
  85. #endif
  86. }
  87. /* Allocate mbuf with associated buffer of 'size' bytes. If interrupts
  88.  * are enabled, use the regular heap. If they're off, use the special
  89.  * interrupt buffer pool.
  90.  */
  91. struct mbuf *
  92. alloc_mbuf(int16 size)
  93. {
  94.     register struct mbuf *bp;
  95. #if !defined(OS2)
  96.     if(istate()){
  97. #else
  98.     if(1){    /* OS/2 is always safe */
  99. #endif
  100.         /* Interrupts are enabled, use the heap normally */
  101.         bp = (struct mbuf *)malloc((unsigned)(size + sizeof(struct mbuf)));
  102.         if(bp == NULLBUF)
  103.             return NULLBUF;
  104.         /* Clear just the header portion */
  105.         memset((char *)bp,0,sizeof(struct mbuf));
  106.         if((bp->size = size) != 0)
  107.             bp->data = (char *)(bp + 1);
  108.         bp->refcnt++;
  109.     } else {
  110.         /* Interrupts are off, use special interrupt buffer pool */
  111.         if(size > Ibufsize || Intq == NULLBUF){
  112.             Ibuffail++;
  113.             return NULLBUF;
  114.         }
  115.         bp = Intq;
  116.         Intq = bp->next;
  117.         bp->next = NULLBUF;
  118.         Intqlen--;
  119.     }
  120.     if(Intqlen < Iminfree)
  121.         Iminfree = Intqlen;
  122.     return bp;
  123. }
  124. /* Allocate mbuf, waiting if memory is unavailable */
  125. struct mbuf *
  126. ambufw(int16 size)
  127. {
  128.     register struct mbuf *bp;
  129.  
  130.     bp = (struct mbuf *)mallocw((unsigned)(size + sizeof(struct mbuf)));
  131.  
  132.     /* Clear just the header portion */
  133.     memset((char *)bp,0,sizeof(struct mbuf));
  134.     if((bp->size = size) != 0)
  135.         bp->data = (char *)(bp + 1);
  136.     bp->refcnt++;
  137.     return bp;
  138. }
  139.  
  140. /* Decrement the reference pointer in an mbuf. If it goes to zero,
  141.  * free all resources associated with mbuf.
  142.  * Return pointer to next mbuf in packet chain
  143.  */
  144. struct mbuf *
  145. free_mbuf(bp)
  146. register struct mbuf *bp;
  147. {
  148.     struct mbuf *bpnext;
  149.  
  150.     if(bp == NULLBUF)
  151.         return NULLBUF;
  152.  
  153.     bpnext = bp->next;
  154.     if(bp->dup != NULLBUF){
  155.         free_mbuf(bp->dup);    /* Follow indirection */
  156.         bp->dup = NULLBUF;
  157.     }
  158.     /* Decrement reference count. If it has gone to zero, free it. */
  159.     if(--bp->refcnt <= 0){
  160. #if !defined(OS2)
  161.         if(istate()){
  162. #else
  163.         if(1){    /* OS/2 is always safe */
  164. #endif
  165.             free((char *)bp);
  166.         } else {
  167.             /* If the interrupt pool isn't full and this buffer
  168.              * appears to have come from it, put it back.
  169.              * Otherwise put it on the garbage list where it
  170.              * will be freed by refiq() later with interrupts
  171.              * enabled.
  172.              *
  173.              * This test handles the common special case of
  174.              * an interrupt handler allocating a buffer and
  175.              * then freeing it before returning (e.g., due to
  176.              * a receive abort or CRC failure).
  177.              */
  178.             bp->refcnt = 1;    /* Adjust */
  179.             if(bp->size == Ibufsize && Intqlen < Nibufs){
  180.                 bp->next = Intq;
  181.                 bp->anext = NULLBUF;
  182.                 bp->data = (char *)(bp + 1);
  183.                 bp->cnt = 0;
  184.                 Intq = bp;
  185.                 Intqlen++;
  186.             } else {
  187.                 bp->next = Garbq;
  188.                 Garbq = bp;
  189.             }
  190.         }
  191.     }
  192.     return bpnext;
  193. }
  194.  
  195. /* Free packet (a chain of mbufs). Return pointer to next packet on queue,
  196.  * if any
  197.  */
  198. struct mbuf *
  199. free_p(bp)
  200. register struct mbuf *bp;
  201. {
  202.     register struct mbuf *abp;
  203.  
  204.     if(bp == NULLBUF)
  205.         return NULLBUF;
  206.     abp = bp->anext;
  207.     while(bp != NULLBUF)
  208.         bp = free_mbuf(bp);
  209.     return abp;
  210. }        
  211. /* Free entire queue of packets (of mbufs) */
  212. void
  213. free_q(q)
  214. struct mbuf **q;
  215. {
  216.     register struct mbuf *bp;
  217.  
  218.     while((bp = dequeue(q)) != NULLBUF)
  219.         free_p(bp);
  220. }
  221.  
  222. /* Count up the total number of bytes in a packet */
  223. int16
  224. len_p(bp)
  225. register struct mbuf *bp;
  226. {
  227.     register int16 cnt = 0;
  228.  
  229.     while(bp != NULLBUF){
  230.         cnt += bp->cnt;
  231.         bp = bp->next;
  232.     }
  233.     return cnt;
  234. }
  235. /* Count up the number of packets in a queue */
  236. int16
  237. len_q(bp)
  238. register struct mbuf *bp;
  239. {
  240.     register int16 cnt;
  241.  
  242.     for(cnt=0;bp != NULLBUF;cnt++,bp = bp->anext)
  243.         ;
  244.     return cnt;
  245. }
  246. /* Trim mbuf to specified length by lopping off end */
  247. void
  248. trim_mbuf(struct mbuf **bpp, int16 length)
  249. {
  250.     register int16 tot = 0;
  251.     register struct mbuf *bp;
  252.  
  253.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  254.         return;    /* Nothing to trim */
  255.  
  256.     if(length == 0){
  257.         /* Toss the whole thing */
  258.         free_p(*bpp);
  259.         *bpp = NULLBUF;
  260.         return;
  261.     }
  262.     /* Find the point at which to trim. If length is greater than
  263.      * the packet, we'll just fall through without doing anything
  264.      */
  265.     for( bp = *bpp; bp != NULLBUF; bp = bp->next){
  266.         if(tot + bp->cnt < length){
  267.             tot += bp->cnt;
  268.         } else {
  269.             /* Cut here */
  270.             bp->cnt = length - tot;
  271.             free_p(bp->next);
  272.             bp->next = NULLBUF;
  273.             break;
  274.         }
  275.     }
  276. }
  277. /* Duplicate/enqueue/dequeue operations based on mbufs */
  278.  
  279. /* Duplicate first 'cnt' bytes of packet starting at 'offset'.
  280.  * This is done without copying data; only the headers are duplicated,
  281.  * but without data segments of their own. The pointers are set up to
  282.  * share the data segments of the original copy. The return pointer is
  283.  * passed back through the first argument, and the return value is the
  284.  * number of bytes actually duplicated.
  285.  */
  286. int16
  287. dup_p(struct mbuf **hp, struct mbuf *bp, int16 offset, int16 cnt)
  288. {
  289.     register struct mbuf *cp;
  290.     int16 tot;
  291.  
  292.     if(cnt == 0 || bp == NULLBUF || hp == NULLBUFP){
  293.         if(hp != NULLBUFP)
  294.             *hp = NULLBUF;
  295.         return 0;
  296.     }
  297.     if((*hp = cp = alloc_mbuf(0)) == NULLBUF){
  298.         return 0;
  299.     }
  300.     /* Skip over leading mbufs that are smaller than the offset */
  301.     while(bp != NULLBUF && bp->cnt <= offset){
  302.         offset -= bp->cnt;
  303.         bp = bp->next;
  304.     }
  305.     if(bp == NULLBUF){
  306.         free_mbuf(cp);
  307.         *hp = NULLBUF;
  308.         return 0;    /* Offset was too big */
  309.     }
  310.     tot = 0;
  311.     for(;;){
  312.         /* Make sure we get the original, "real" buffer (i.e. handle the
  313.          * case of duping a dupe)
  314.          */
  315.         if(bp->dup != NULLBUF)
  316.             cp->dup = bp->dup;
  317.         else
  318.             cp->dup = bp;
  319.  
  320.         /* Increment the duplicated buffer's reference count */
  321.         cp->dup->refcnt++;
  322.  
  323.         cp->data = bp->data + offset;
  324.         cp->cnt = min(cnt,bp->cnt - offset);
  325.         offset = 0;
  326.         cnt -= cp->cnt;
  327.         tot += cp->cnt;
  328.         bp = bp->next;
  329.         if(cnt == 0 || bp == NULLBUF || (cp->next = alloc_mbuf(0)) == NULLBUF)
  330.             break;
  331.         cp = cp->next;
  332.     }
  333.     return tot;
  334. }
  335. /* Copy first 'cnt' bytes of packet into a new, single mbuf */
  336. struct mbuf *
  337. copy_p(struct mbuf *bp, int16 cnt)
  338. {
  339.     register struct mbuf *cp;
  340.     register char *wp;
  341.     register int16 n;
  342.  
  343.     if(bp == NULLBUF || cnt == 0 || (cp = alloc_mbuf(cnt)) == NULLBUF)
  344.         return NULLBUF;
  345.     wp = cp->data;
  346.     while(cnt != 0 && bp != NULLBUF){
  347.         n = min(cnt,bp->cnt);
  348.         memcpy(wp,bp->data,n);
  349.         wp += n;
  350.         cp->cnt += n;
  351.         cnt -= n;
  352.         bp = bp->next;
  353.     }
  354.     return cp;
  355. }
  356. /* Copy and delete "cnt" bytes from beginning of packet. Return number of
  357.  * bytes actually pulled off
  358.  */
  359. int16
  360. pullup(struct mbuf **bph, char *buf, int16 cnt)
  361. {
  362.     register struct mbuf *bp;
  363.     int16 n,tot;
  364.  
  365.     tot = 0;
  366.     if(bph == NULLBUFP)
  367.         return 0;
  368.     while(cnt != 0 && (bp = *bph) != NULLBUF){
  369.         n = min(cnt,bp->cnt);
  370.         if(buf != NULLCHAR){
  371.             if(n == 1)    /* Common case optimization */
  372.                 *buf = *bp->data;
  373.             else if(n > 1)
  374.                 memcpy(buf,bp->data,n);
  375.             buf += n;
  376.         }
  377.         tot += n;
  378.         cnt -= n;
  379.         bp->data += n;
  380.         bp->cnt -= n;        
  381.         if(bp->cnt == 0){
  382.             /* If this is the last mbuf of a packet but there
  383.              * are others on the queue, return a pointer to
  384.              * the next on the queue. This allows pullups to
  385.              * to work on a packet queue
  386.              */
  387.             if(bp->next == NULLBUF && bp->anext != NULLBUF){
  388.                 *bph = bp->anext;
  389.                 free_mbuf(bp);
  390.             } else
  391.                 *bph = free_mbuf(bp);
  392.         }
  393.     }
  394.     return tot;
  395. }
  396. /* Append mbuf to end of mbuf chain */
  397. void
  398. append(bph,bp)
  399. struct mbuf **bph;
  400. struct mbuf *bp;
  401. {
  402.     register struct mbuf *p;
  403.  
  404.     if(bph == NULLBUFP || bp == NULLBUF)
  405.         return;
  406.     if(*bph == NULLBUF){
  407.         /* First one on chain */
  408.         *bph = bp;
  409.     } else {
  410.         for(p = *bph ; p->next != NULLBUF ; p = p->next)
  411.             ;
  412.         p->next = bp;
  413.     }
  414. }
  415. /* Insert specified amount of contiguous new space at the beginning of an
  416.  * mbuf chain. If enough space is available in the first mbuf, no new space
  417.  * is allocated. Otherwise a mbuf of the appropriate size is allocated and
  418.  * tacked on the front of the chain.
  419.  *
  420.  * This operation is the logical inverse of pullup(), hence the name.
  421.  */
  422. struct mbuf *
  423. pushdown(struct mbuf *bp, int16 size)
  424. {
  425.     register struct mbuf *nbp;
  426.  
  427.     /* Check that bp is real, that it hasn't been duplicated, and
  428.      * that it itself isn't a duplicate before checking to see if
  429.      * there's enough space at its front.
  430.      */
  431.     if(bp != NULLBUF && bp->refcnt == 1 && bp->dup == NULLBUF
  432.      && bp->data - (char *)(bp+1) >= size){
  433.         /* No need to alloc new mbuf, just adjust this one */
  434.         bp->data -= size;
  435.         bp->cnt += size;
  436.     } else {
  437.         nbp = ambufw(size);
  438.         nbp->next = bp;
  439.         nbp->cnt = size;
  440.         bp = nbp;
  441.     }
  442.     return bp;
  443. }
  444. /* Append packet to end of packet queue */
  445. void
  446. enqueue(q,bp)
  447. struct mbuf **q;
  448. struct mbuf *bp;
  449. {
  450.     register struct mbuf *p;
  451.     char i_state;
  452.  
  453.     if(q == NULLBUFP || bp == NULLBUF)
  454.         return;
  455.     i_state = dirps();
  456.     if(*q == NULLBUF){
  457.         /* List is empty, stick at front */
  458.         *q = bp;
  459.     } else {
  460.         for(p = *q ; p->anext != NULLBUF ; p = p->anext)
  461.             ;
  462.         p->anext = bp;
  463.     }
  464.     restore(i_state);
  465.     psignal(q,1);
  466. }
  467. /* Unlink a packet from the head of the queue */
  468. struct mbuf *
  469. dequeue(q)
  470. register struct mbuf **q;
  471. {
  472.     register struct mbuf *bp;
  473.     char i_state;
  474.  
  475.     if(q == NULLBUFP)
  476.         return NULLBUF;
  477.     i_state = dirps();
  478.     if((bp = *q) != NULLBUF){
  479.         *q = bp->anext;
  480.         bp->anext = NULLBUF;
  481.     }
  482.     restore(i_state);
  483.     return bp;
  484. }    
  485.  
  486. /* Copy user data into an mbuf */
  487. struct mbuf *
  488. qdata(char *data, int16 cnt)
  489. {
  490.     register struct mbuf *bp;
  491.  
  492.     bp = ambufw(cnt);
  493.     memcpy(bp->data,data,cnt);
  494.     bp->cnt = cnt;
  495.     return bp;
  496. }
  497. /* Copy mbuf data into user buffer */
  498. int16
  499. dqdata(bp,buf,cnt)
  500. struct mbuf *bp;
  501. char *buf;
  502. unsigned cnt;
  503. {
  504.     int16 tot;
  505.     unsigned n;
  506.     struct mbuf *bp1;
  507.  
  508.     if(buf == NULLCHAR)
  509.         return 0;
  510.     
  511.     tot = 0;
  512.     for(bp1 = bp;bp1 != NULLBUF; bp1 = bp1->next){
  513.         n = min(bp1->cnt,cnt);
  514.         memcpy(buf,bp1->data,n);
  515.         cnt -= n;
  516.         buf += n;
  517.         tot += n;
  518.     }
  519.     free_p(bp);
  520.     return tot;
  521. }
  522. /* Pull a 32-bit integer in host order from buffer in network byte order.
  523.  * On error, return 0. Note that this is indistinguishable from a normal
  524.  * return.
  525.  */
  526. int32
  527. pull32(bpp)
  528. struct mbuf **bpp;
  529. {
  530.     char buf[4];
  531.  
  532.     if(pullup(bpp,buf,4) != 4){
  533.         /* Return zero if insufficient buffer */
  534.         return 0;
  535.     }
  536.     return get32(buf);
  537. }
  538. /* Pull a 16-bit integer in host order from buffer in network byte order.
  539.  * Return -1 on error
  540.  */
  541. long
  542. pull16(bpp)
  543. struct mbuf **bpp;
  544. {
  545.     char buf[2];
  546.  
  547.     if(pullup(bpp,buf,2) != 2){
  548.         return -1;        /* Nothing left */
  549.     }
  550.     return get16(buf);
  551. }
  552. /* Pull single character from mbuf */
  553. int
  554. pullchar(bpp)
  555. struct mbuf **bpp;
  556. {
  557.     char c;
  558.  
  559.     if(pullup(bpp,&c,1) != 1)
  560.         return -1;        /* Nothing left */
  561.     return (int)uchar(c);
  562. }
  563. int
  564. write_p(fp,bp)
  565. FILE *fp;
  566. struct mbuf *bp;
  567. {
  568.     while(bp != NULLBUF){
  569.         if(fwrite(bp->data,1,bp->cnt,fp) != bp->cnt)
  570.             return -1;
  571.         bp = bp->next;
  572.     }
  573.     return 0;
  574. }
  575. /* Reclaim unused space in a mbuf chain. If the argument is a chain of mbufs
  576.  * and/or it appears to have wasted space, copy it to a single new mbuf and
  577.  * free the old mbuf(s). But refuse to move mbufs that merely
  578.  * reference other mbufs, or that have other headers referencing them.
  579.  *
  580.  * Be extremely careful that there aren't any other pointers to
  581.  * (or into) this mbuf, since we have no way of detecting them here.
  582.  * This function is meant to be called only when free memory is in
  583.  * short supply.
  584.  */
  585. void
  586. mbuf_crunch(bpp)
  587. struct mbuf **bpp;
  588. {
  589.     register struct mbuf *bp = *bpp;
  590.     struct mbuf *nbp;
  591.  
  592.     if(bp->refcnt > 1 || bp->dup != NULLBUF){
  593.         /* Can't crunch, there are other refs */
  594.         return;
  595.     }
  596.     if(bp->next == NULLBUF && bp->cnt == bp->size){
  597.         /* Nothing to be gained by crunching */
  598.         return;
  599.     }
  600.     if((nbp = copy_p(bp,len_p(bp))) == NULLBUF){
  601.         /* Copy failed due to lack of (contiguous) space */
  602.         return;
  603.     }
  604.     nbp->anext = bp->anext;
  605.     free_p(bp);
  606.     *bpp = nbp;
  607. }
  608.